import 'dart:async';

import 'package:flutter/material.dart';
import 'package:get/get.dart';

class RouterStreamData {
  RouterStreamData({this.route, required this.type, this.previousRoute});

  Route<dynamic>? route;
  Route<dynamic>? previousRoute;
  RouteChangeType type;

  @override
  String toString() {
    return "$route---${type.name}---$previousRoute";
  }
}

enum RouteChangeType { push, pop, replace, remove }

class CustomRouteObservers extends NavigatorObserver {
  CustomRouteObservers._();

  static CustomRouteObservers observer = CustomRouteObservers._();

  Stream<RouterStreamData> get stream => _controller.stream;
  final StreamController<RouterStreamData> _controller = StreamController.broadcast();

  @override
  void didPop(Route route, Route? previousRoute) {
    _controller.sink.add(RouterStreamData(route: route, previousRoute: previousRoute, type: RouteChangeType.pop));
  }

  @override
  void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
    _controller.sink.add(RouterStreamData(route: route, previousRoute: previousRoute, type: RouteChangeType.push));
  }

  @override
  void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
    _controller.sink.add(RouterStreamData(route: newRoute, previousRoute: oldRoute, type: RouteChangeType.replace));
  }

  @override
  void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) {
    _controller.sink.add(RouterStreamData(route: route, previousRoute: previousRoute, type: RouteChangeType.replace));
  }
}

mixin RouterObserverStateMixin<T extends StatefulWidget> on State<T> {
  late StreamSubscription<RouterStreamData> observer;

  @override
  void initState() {
    super.initState();
    observer = CustomRouteObservers.observer.stream.listen(listenRouteChange);
  }

  void listenRouteChange(RouterStreamData event);

  @override
  void dispose() {
    observer.cancel();
    super.dispose();
  }
}

mixin RouterObserverGetxMixin on GetxController {
  late StreamSubscription<RouterStreamData> observer;

  @override
  void onInit() {
    super.onInit();
    observer = CustomRouteObservers.observer.stream.listen(listenRouteChange);
  }

  void listenRouteChange(RouterStreamData event);
  
  @override
  void onClose() {
    observer.cancel();
    super.onClose();
  }
}
